{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# General Mølmer-Sørensen Gate\n",
    "\n",
    "*Copyright (c) 2021 Institute for Quantum Computing, Baidu Inc. All Rights Reserved.*"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Outline\n",
    "This tutorial will demonstrate how to implement the general Mølmer-Sørensen gate and Greenberger–Horne–Zeilinger (GHZ) state in trapped ion quantum computing platform using Quanlse. The outline of this tutorial is as follows:\n",
    "\n",
    "\n",
    "- Introduction to general Mølmer-Sørensen gate in trapped ion\n",
    "- Preperation\n",
    "- Pulse generator of general Mølmer-Sørensen gate\n",
    "- Generate GHZ state using general Mølmer-Sørensen gate\n",
    "- Summary\n",
    "- Reference"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Introduction to general Mølmer-Sørensen gate in trapped ion\n",
    "\n",
    "The major difference between the trapped ion quantum computing platform and other platforms is that ions can transmit information by collective vibrations-phonon. The ions in a 1-dimensional line share the same phonons, which reveals that all qubits can be connected easily through the implementation of some laser pulses. The benefits of the all-to-all connection in trapped ions will bring some unique influence. One of the important application is to realize the entangled state of multi-qubits GHZ state \\[1\\]\\[2\\]. We have introduced the two-qubits Mølmer-Sørensen gate in [Trapped Ion Singe/Two-qubit Gate](https://quanlse.baidu.com/#/doc/tutorial-ion-trap-single-and-two-qubit-gate). For the general Mølmer-Sørensen gate，by using the same derivative process, the system Hamiltonian implemented by multi-lasers can be written as follows:\n",
    "\n",
    "$$\n",
    "\\hat{H}_{\\rm M S}= \\hbar \\sum_{j=0}^M \\Omega_{j}(t) \\hat{{\\sigma}}_{x}^{j}\\sum_{k=1}^{N}\\eta_{j,k}e^{i\\mu t}\\left(\\hat{a}_k e^{-i \\omega_{k} t}+\\hat{a}_k^{\\dagger} e^{i \\omega_{k} t}\\right)+\\rm {\\rm H.c.}, \n",
    "$$\n",
    "where $j,k$ denote the ion and phonon indexes, $M$ is the number of ions implemented by laser. $N$ denotes the total ion number in the chain which also represents the phonon number in ion chain. $\\mu$ denotes the laser detuning which is related to the gate time with $\\mu=2\\pi/t_g$. $\\hat{\\sigma}_x^j$ is the $j_{th}$ ion Pauli matrix, $\\hat a_k^\\dagger,\\hat a_k$ denote the $k_{th}$ phonon creation and annihilation operation. $\\Omega_j(t)$ is the pulse sequences which need to be optimized. $\\eta_{j,k}$ is the Lamb-Dicke parameters of phonon mode，$\\omega_k$ represents the vibration frequency of $k_{th}$ phonon. For convenience, we set $\\hbar=1$ for the following sections.\n",
    "\n",
    "In the Lamb-Dicke parameter $\\eta_{j,k}\\ll 1$ regime, the time-dependent evolution of the effective Hamiltonian can be expanded to the 2-order of Magnus formula：\n",
    "\n",
    "$$\n",
    "U(t_g)=\\exp \\left[-i\\sum_{j=0}^M \\hat{\\sigma}_{x}^{j}\\sum_{k=1}^{N}\\left(\\alpha_{j, k}(t_g) \\hat{a}_{k}^{\\dagger}-\\alpha_{j, k}^{*}(t_g) \\hat{a}_{k}\\right) +i\\sum_{m<n}^M\\chi_{m,n}(t_g)\\hat{\\sigma}_{x}^{m}\\hat{\\sigma}_{x}^{n}\\right], \n",
    "$$\n",
    "\n",
    "where $\\alpha_{j, k}(t_g)=\\int_0^{t_g} dt f(\\eta_{k,j},\\Omega_j(t),\\omega_k)$，$\\chi_{m,n}(t_g)=\\sum_k\\int_0^{t_g} dt\\int_0^{t} dt_1 g(\\eta_{k,j},\\Omega_m(t), \\Omega_n(t_1), \\omega_k)$.\n",
    "The first term represents the coupling between phonon $k$ and ion $j$, and the second term represents the coupling between ion $m$ and ion $n$. In order to reach the maximum entanglement between all ion pairs after the gate time $t_g$ period, we need to make sure the unitary matrix equation term $\\alpha_{j, k}(t_g)\\to 0, \\chi_{m,n}(t_g)\\to \\pi/4$. When the pair number $\\{m, n\\}$ are more than 1, we call such unitary matrix $U({t_g})$ general Mølmer-Sørensen gate. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Preperation\n",
    "\n",
    "First of all, after successfully installing Quansle, users need to import the required package from Quanlse and some specific Python libraries:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Import the necessary packages\n",
    "from Quanlse.remoteOptimizer import remoteIonGeneralMS as pulseGeneralMS\n",
    "from Quanlse.Utils import Plot\n",
    "\n",
    "import sys\n",
    "import numpy as np\n",
    "from math import pi"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To use Quanlse Cloud Service, users can get a token from http://quantum-hub.baidu.com and submit the job onto Quanlse's cloud server: "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from Quanlse import Define\n",
    "# Your token:\n",
    "# Please visit http://quantum-hub.baidu.com\n",
    "Define.hubToken = \"\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Pulse generator of general Mølmer-Sørensen gate\n",
    "\n",
    "Next, we will show how to generate the pulse sequences of the general Mølmer-Sørensen gate and the pulses of 4-qubits GHZ statem by Quanlse Trapped Ion. First of all, we need to set the linear trapped ion system parameters, including the atom mass `mass`，the total number in the 1-dimensional trap `ionNumber`, trap potential frequency `omega`, and transmit information phonon mode `phononMode`. All those constitute the `args1`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Define the system information\n",
    "ionNumber = 7  # System qubit number\n",
    "mass = 171  # System ion mass\n",
    "omegaXY = 2 * pi * 2e6  # XY direction trap potential frequency\n",
    "omegaZ = 2 * pi * 0.2e6  # Z direction trap potential frequency, usually omegaZ << omegaXY\n",
    "phononMode = \"transverse\"  # Phonon mode which users can choose \"transverse\" or \"axial\" \n",
    "\n",
    "# Combine the parameter in Tuple\n",
    "args1 = (ionNumber, mass, omegaXY, omegaZ, phononMode)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "At the same time, we also need to define the gate parameters, including gate time `tgate`, laser detuning `mu`, and pulse sequence number `N`. All these constitute `args2`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Define the gate information\n",
    "tgate = 200  # Total time of quantum gate\n",
    "mu = 2 * pi / tgate  # The laser detuning, usually related with gate time. but can tuning around 2 * pi / tgate\n",
    "N = 35  # The pulse sequence slice number, usually N > 3 * ionNumber\n",
    "dt = tgate / N  # Sample time\n",
    "\n",
    "# Combine the parameter in Tuple\n",
    "args2 = (N, dt, mu)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Because of the all to all connection characteristic of trapped ions, users need to assign the qubits pair `gatePair` implemented by laser, the `gatePair` is formed by the list$\\{[m,n]\\}(m \\neq n)$ of $\\chi_{m,n}(t_g)$. For the parallel Mølmer-Sørensen gate, we can define the ion pair parameters as follows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Define the gate pair of general Molmer-Sorensen gate\n",
    "gatePair = ([0, 1], [2, 3], [4, 5])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "By running `pulseGeneralMS()` function, we can generate the pulse sequences information of general Mølmer-Sørensen gate:\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "res, ureal = pulseGeneralMS(gatePair, args1=args1, args2=args2)\n",
    "print(\"The generated unitary gate is:\\n\", np.round(ureal, 2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Using Quanlse Trapped Ion, users can calculate the gate infidelity of general Mølmer-Sørensen gate and print the result:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Print the infidelity of general MS gate\n",
    "print(f\"The parallel Mølmer-Sørensen gate infidelity:\\n {res['infidelity']}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Users can also visualize the pulse sequences easliy by using Quanlse's plot module:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pulse = res['pulse_list']\n",
    "ionpair = gatePair.index([4, 5])  # Choose the pulse sequence of ionpair\n",
    "Plot.plotPulse([np.arange(N) * dt * (N+1) / N], [pulse[ionpair]],\n",
    "               title=[f'Pulse for ionpair={gatePair[ionpair]} '],\n",
    "               xLabel=r'Time ($\\mu$s)', yLabel=['Rabi frequency (a.u)'], color=['blue'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Generate GHZ states using general Mølmer-Sørensen gate\n",
    "\n",
    "The most important advantage of the general Mølmer-Sørensen gate is convenience and efficiency, general Mølmer-Sørensen gate can easily generate multi-qubits GHZ state. Let’s take a 4-qubits GHZ state as an example, and illustrate users how to use the ion trap pulse to generate a 4-qubits GHZ state $|\\rm GHZ\\rangle_{4}=\\frac{|0000\\rangle+|1111\\rangle}{\\sqrt 2}$. For unitary matrix $U(t_g)$, the 4-qubit corresponding index $M=3$, and the 4-qubits GHZ state unitary requires $\\chi_{0,1}(t_g)=\\chi_{0,2}(t_g)=\\chi_{0,3}(t_g)=\\chi_{1,2}(t_g)=\\chi_{1,3}(t_g)=\\chi_{2,3}(t_g)=\\pi/4$, so we can set `gatePair` as follows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Define the gate pair of general Molmer-Sorensen gate\n",
    "gatePair = ([0, 1], [0, 2], [0, 3], [1, 2], [1, 3], [2, 3])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "By using `pulseGeneralMS()` function, we can generate the pulse required for the 4-qubits GHZ state, the corresponding unitary matrix, and the gate infidelity:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "res, ureal = pulseGeneralMS(gatePair, args1=args1, args2=args2)\n",
    "print(\"The generated unitary gate is:\\n\", np.round(ureal, 2))\n",
    "print(f\"The parallel Mølmer-Sørensen gate infidelity:\\n {res['infidelity']}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In order to visualize the effect of the general Mølmer-Sørensen gate, users can calculate the distribution of the final GHZ state on the multi-qubits basis after implement the general Mølmer-Sørensen gate. We first need to import the relevant base vector generation and drawing package from Quanlse:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Import the function for qubit basis\n",
    "from Quanlse.Utils.Functions import basis\n",
    "from Quanlse.Utils.Functions import computationalBasisList\n",
    "# Import the function for plot bar figures\n",
    "from Quanlse.Utils.Plot import plotBarGraph"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Then through the unitary matrix generated by the Quanlse Trapped Ion, we can calculate the final GHZ state and it’s population distribution after implementing the operation:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "finalState = (ureal @ np.array(basis(16, 0))).T[0] # Get final state \n",
    "population = [abs(state ** 2) for state in finalState] # calulate the states distribution\n",
    "basis = computationalBasisList(4, 2) # define the qubit basis list"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Using the drawing package of Quanlse, users can visualize the population of final GHZ state:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plotBarGraph(basis, population, \"Population of a 4-Qubits GHZ state generated by General Mølmer-Sørensen gate\",\n",
    "             \"Computational Basis\", \"Population\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "After implemented the general Mølmer-Sørensen gate generated by Quanlse Trapped Ion, final state is distributed in basis $|0000\\rangle$ and $|1111\\rangle$ mostly."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Summary\n",
    "\n",
    "Thanks to the fully connected feature of trapped ions, users can use the general Mølmer-Sørensen gate pulse generation function supported by Quanlse to quickly generate parallel Mølmer-Sørensen laser pulses, and visualize the population of the GHZ state generated by general Mølmer-Sørensen gate. Users can click on the link [tutorial-general-MSgate.ipynb](https://github.com/baidu/Quanlse/blob/main/Tutorial/EN/tutorial-general-MS-gate.ipynb) to jump to Jupyter Notebook document of the corresponding GitHub page and obtain the relevant code to run the program."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Reference\n",
    "\n",
    "\\[1\\] [Figgatt, Caroline, et al. \"Parallel entangling operations on a universal ion-trap quantum computer.\" *Nature* 572.7769 (2019): 368-372.](https://www.nature.com/articles/s41586-019-1427-5)\n",
    "\n",
    "\\[2\\] [Lu, Yao, et al. \"Global entangling gates on arbitrary ion qubits.\" *Nature* 572.7769 (2019): 363-367.](https://www.nature.com/articles/s41586-019-1428-4)"
   ]
  }
 ],
 "metadata": {
  "interpreter": {
   "hash": "6b492610b12c5527f6547446ce2a29ad5c1ce3bfe5e6c0e554dc04678ce49b99"
  },
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.12"
  },
  "metadata": {
   "interpreter": {
    "hash": "8d363e4bfcef2c3c01fa47154ae7e88cf48cc82f780560a505e7e79a59b7edb7"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
